/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package cz.muni.fi.diplomka.webapp.army;

import cz.fi.muni.diplomka.common.Coordinates;
import cz.fi.muni.diplomka.common.Squad;
import cz.fi.muni.diplomka.common.enumeration.MovementType;
import cz.fi.muni.diplomka.common.enumeration.TileType;
import cz.muni.fi.diplomka.servicelayer.dto.City;
import cz.muni.fi.diplomka.servicelayer.dto.CityArmy;
import cz.muni.fi.diplomka.servicelayer.dto.MarchingArmy;
import cz.muni.fi.diplomka.servicelayer.dto.Player;
import cz.muni.fi.diplomka.servicelayer.dto.Research;
import cz.muni.fi.diplomka.servicelayer.gamelogic.manager.AlliancesManager;
import cz.muni.fi.diplomka.servicelayer.gamelogic.manager.CityArmyManager;
import cz.muni.fi.diplomka.servicelayer.gamelogic.manager.CityManager;
import cz.muni.fi.diplomka.servicelayer.gamelogic.manager.ResearchManager;
import cz.muni.fi.diplomka.servicelayer.gamelogic.manager.MarchingArmyManager;
import cz.muni.fi.diplomka.servicelayer.gamelogic.manager.PlayerManager;
import cz.muni.fi.diplomka.servicelayer.gamelogic.manager.WorldManager;
import cz.muni.fi.diplomka.servicelayer.gamelogic.managerimpl.AlliancesManagerImpl;
import cz.muni.fi.diplomka.servicelayer.gamelogic.managerimpl.CityArmyManagerImpl;
import cz.muni.fi.diplomka.servicelayer.gamelogic.managerimpl.CityManagerImpl;
import cz.muni.fi.diplomka.servicelayer.gamelogic.managerimpl.ResearchManagerImpl;
import cz.muni.fi.diplomka.servicelayer.gamelogic.managerimpl.MarchingArmyManagerImpl;
import cz.muni.fi.diplomka.servicelayer.gamelogic.managerimpl.PlayerManagerImpl;
import cz.muni.fi.diplomka.servicelayer.gamelogic.managerimpl.WorldManagerImpl;
import cz.muni.fi.diplomka.servicelayer.gamelogic.resolver.TravelDistanceResolver;
import cz.muni.fi.diplomka.webapp.layout.LinkPanel;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.wicket.PageParameters;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.DropDownChoice;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.markup.html.panel.FeedbackPanel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;

/**
 *
 * @author Jakub Kutil
 */
public class ArmyPage extends WebPage {

    private CityManager cityManager = new CityManagerImpl();
    private CityArmyManager cityArmyManager = new CityArmyManagerImpl();
    private MarchingArmyManager marchingArmyManager = new MarchingArmyManagerImpl();
    private PlayerManager playerManager = new PlayerManagerImpl();
    private WorldManager worldManager = new WorldManagerImpl();
    private AlliancesManager alliancesManager = new AlliancesManagerImpl();
    private ResearchManager cityResearchManager = new ResearchManagerImpl();
    private String selectedCity = "";
    private List<String> cities;

    public ArmyPage(PageParameters parameters) {
        final Long id;

        add(new FeedbackPanel("feedback"));

        if (parameters.containsKey("id")) {
            id = Long.parseLong(parameters.getString("id"));
            PageParameters p = new PageParameters();
            p.add("id", parameters.getString("id"));
            add(new LinkPanel("linkPanel", p));
            add(new ArmyPanel("armyPanel", p));

            cities = new ArrayList<>();
            for (City c : cityManager.getCitiesByPlayerId(id)) {
                cities.add(c.getName());
            }
            if (parameters.containsKey("cityName")) {
                selectedCity = parameters.getString("cityName");
            }

            if (selectedCity.equals("")) {
                selectedCity = cities.get(0).toString();
            }

            p.add("cityName", selectedCity);

            final DropDownChoice<String> city = new DropDownChoice<>("city",
                    new PropertyModel<String>(this, "selectedCity"), cities);

            Form<?> selectCity = new Form<Void>("selectCity") {
                @Override
                protected void onSubmit() {
                    selectedCity = cities.get(Integer.parseInt(city.getValue()));
                    PageParameters pageParameters = new PageParameters();
                    pageParameters.add("id", id.toString());
                    pageParameters.add("cityName", selectedCity);
                    setResponsePage(ArmyPage.class, pageParameters);
                }
            };

            add(selectCity);
            selectCity.add(city);

            List<CityArmy> list = new ArrayList<>();


            for (CityArmy cityArmy : cityArmyManager.getArmiesInCity(cityManager.getCityByName(selectedCity).getId())) {
                list.add(cityArmy);
            }

            ListView listview = new ListView("listview", list) {
                @Override
                protected void populateItem(ListItem item) {
                    final CityArmy cityArmy = (CityArmy) item.getModelObject();
                    item.add(new Label("name", cityArmy.getName()));
                    item.add(new Label("owner", cityManager.getOwnerOfCity(cityArmy.getOwnerCityId()).getNickName() + ", city: " + cityManager.getCityById(cityArmy.getOwnerCityId()).getName()));
                    item.add(new Label("walls", cityArmy.isGuard() ? "yes" : "no"));
                    String units = "";
                    for (Squad squad : cityArmy.getArmy().getSquads()) {
                        units += squad.getUnit().getName() + ": " + (int) squad.getCount() + ", threshold: " + (int) squad.getThreshold() + " % ";
                    }
                    item.add(new Label("units", units));

                    final TextField<String> xCoordinate = new TextField<>("xCoordinate", Model.of("0"));

                    final TextField<String> yCoordinate = new TextField<>("yCoordinate", Model.of("0"));


                    final List<String> TYPE = Arrays.asList(new String[]{
                        "Attack", "Reinforcement", "Support"});

                    final DropDownChoice<String> type = new DropDownChoice<>("type", Model.of("Attack"), TYPE);

                    Form<?> send = new Form<Void>("send") {
                        @Override
                        protected void onSubmit() {
                            PageParameters pageParameters = new PageParameters();
                            pageParameters.add("id", id.toString());

                            boolean ok = true;
                            MarchingArmy army = new MarchingArmy();

                            switch (type.getValue()) {
                                case "0":
                                    army.setMovement(MovementType.Attack);
                                    break;
                                case "1":
                                    army.setMovement(MovementType.Reinforcement);
                                    break;
                                case "2":
                                    army.setMovement(MovementType.Support);
                                    break;
                            }

                            Coordinates c = new Coordinates();
                            try {
                                c.setX_coordinate(Integer.parseInt(xCoordinate.getValue()));
                                c.setY_coordinate(Integer.parseInt(yCoordinate.getValue()));
                            } catch (NumberFormatException ex) {
                                error("Coordinates has to be numbers.");
                                ok = false;
                            }
                            if (c.getX_coordinate() < worldManager.getUpperLeftCorner().getX_coordinate()
                                    || c.getY_coordinate() > worldManager.getUpperLeftCorner().getY_coordinate()
                                    || c.getX_coordinate() > worldManager.getLowerRightCorner().getX_coordinate()
                                    || c.getY_coordinate() < worldManager.getLowerRightCorner().getY_coordinate()) {
                                error("Out of bound of world.");
                                ok = false;
                            }

                            if (worldManager.getTileAtPosition(c.getX_coordinate(), c.getY_coordinate()).getType() == TileType.plain) {
                                error("There are only plains on that position. No need to send army there.");
                                ok = false;
                            }
                            if (worldManager.getTileAtPosition(c.getX_coordinate(), c.getY_coordinate()).getType() == TileType.city) {
                                Player player = cityManager.getOwnerOfCity(cityManager.getCityAtPosition(c).getId());
                                if (alliancesManager.getAllianceOfPlayer(player.getId()).getId() != null
                                        && alliancesManager.getAllianceOfPlayer(player.getId()).getName().equals(alliancesManager.getAllianceOfPlayer(cityManager.getOwnerOfCity(cityArmy.getOwnerCityId()).getId()).getName())
                                        && army.getMovement() == MovementType.Attack) {
                                    error("You can not attack your ally or yourself.");
                                    ok = false;
                                }
                            } else {
                                army.setMovement(MovementType.Attack);
                            }

                            if (ok == true) {
                                army.setArmy(cityArmy.getArmy());

                                army.setCityIdFrom(cityArmy.getCityId());
                                army.setCoordinates(c);
                                army.setName(cityArmy.getName());
                                army.setOwnerCityId(cityArmy.getOwnerCityId());
                                army.setReturning(false);
                                army.setStolenFood(0);
                                army.setStolenGold(0);
                                army.setStolenStone(0);

                                TravelDistanceResolver travelDistanceResolver = new TravelDistanceResolver();
                                double distance = travelDistanceResolver.calculateDistance(c.getX_coordinate(), c.getY_coordinate(),
                                        cityManager.getCityByName(selectedCity).getCoordinates().getX_coordinate(), cityManager.getCityByName(selectedCity).getCoordinates().getY_coordinate());

                                int bonusSpeed = 0;
                                for (Research research : cityResearchManager.getAllFinishedResearchesOfPlayer(cityManager.getOwnerOfCity(cityArmy.getCityId()).getId())) {
                                    for (String stat : research.getEffects().keySet()) {
                                        if (stat.equals("speed")) {
                                            bonusSpeed += research.getEffects().get(stat);
                                        }
                                    }
                                }

                                int minSpeed = 500;
                                for (Squad squad : army.getArmy().getSquads()) {
                                    if (minSpeed > (squad.getUnit().getSpeed() + bonusSpeed)) {
                                        minSpeed = squad.getUnit().getSpeed() + bonusSpeed;
                                    }
                                }

                                java.util.Date date = new java.util.Date();
                                army.setTimeOfArrival(new Timestamp((date.getTime() + 1000 * 60 * (int) (distance / minSpeed))));

                                marchingArmyManager.createMarchingArmy(army);
                                cityArmyManager.sendArmy(cityArmy);
                                setResponsePage(ArmyPage.class, pageParameters);
                            }
                        }
                    };

                    send.add(xCoordinate);
                    send.add(yCoordinate);
                    send.add(type);

                    item.add(send);

                    Form<?> sendToWalls = new Form<Void>("sendToWalls") {
                        @Override
                        protected void onSubmit() {
                            PageParameters pageParameters = new PageParameters();
                            pageParameters.add("id", id.toString());

                            CityArmy toMove = cityArmyManager.getArmyOnCityWalls(cityManager.getCityByName(selectedCity).getId());
                            if (toMove != null) {
                                toMove.setGuard(false);
                                cityArmyManager.editArmy(toMove);
                            }
                            cityArmy.setGuard(true);
                            cityArmyManager.editArmy(cityArmy);
                            info("Army has been moved to city walls");
                            setResponsePage(ArmyPage.class, pageParameters);
                        }
                    };

                    item.add(sendToWalls);

                    Form<?> disbandArmy = new Form<Void>("disband") {
                        @Override
                        protected void onSubmit() {
                            PageParameters pageParameters = new PageParameters();
                            pageParameters.add("id", id.toString());

                            if (cityArmy.getOwnerCityId() != cityArmy.getCityId()) {
                                MarchingArmy army = new MarchingArmy();

                                City city = cityManager.getCityById(cityArmy.getOwnerCityId());
                                Coordinates c = new Coordinates();

                                c.setX_coordinate(city.getCoordinates().getX_coordinate());
                                c.setY_coordinate(city.getCoordinates().getY_coordinate());

                                army.setArmy(cityArmy.getArmy());

                                army.setCityIdFrom(cityArmy.getCityId());
                                army.setCoordinates(c);
                                army.setName(cityArmy.getName());
                                army.setOwnerCityId(cityArmy.getOwnerCityId());
                                army.setReturning(true);
                                army.setMovement(MovementType.Reinforcement);
                                army.setStolenFood(0);
                                army.setStolenGold(0);
                                army.setStolenStone(0);

                                TravelDistanceResolver travelDistanceResolver = new TravelDistanceResolver();
                                double time = travelDistanceResolver.calculateDistance(c.getX_coordinate(), c.getY_coordinate(),
                                        cityManager.getCityByName(selectedCity).getCoordinates().getX_coordinate(), cityManager.getCityByName(selectedCity).getCoordinates().getY_coordinate());

                                double finalTime = new Double(Double.MIN_VALUE);
                                for (Squad squad : army.getArmy().getSquads()) {
                                    if (finalTime < (time / squad.getUnit().getSpeed())) {
                                        finalTime = time / squad.getUnit().getSpeed();
                                    }
                                }
                                java.util.Date date = new java.util.Date();

                                army.setTimeOfArrival(new Timestamp(date.getTime() + (long) finalTime * 1000 * 60));
                                marchingArmyManager.createMarchingArmy(army);
                                cityArmyManager.sendArmy(cityArmy);

                                info("Army has been sent to owner.");
                            } else {
                                cityArmyManager.deleteArmy(cityArmy);
                                info("Army has been disbanded.");
                            }
                            setResponsePage(ArmyPage.class, pageParameters);
                        }
                    };

                    item.add(disbandArmy);
                }
            };
            add(listview);

            List<CityArmy> away = new ArrayList<>();

            for (CityArmy cityArmy : cityArmyManager.getAwayArmiesFromCity(cityManager.getCityByName(selectedCity).getId())) {
                away.add(cityArmy);
            }
            ListView awayArmies = new ListView("awayArmies", away) {
                @Override
                protected void populateItem(ListItem item) {
                    final CityArmy cityArmy = (CityArmy) item.getModelObject();
                    item.add(new Label("name", cityArmy.getName()));
                    item.add(new Label("commander", cityManager.getOwnerOfCity(cityArmy.getCityId()).getNickName() + ", city: " + cityManager.getCityById(cityArmy.getCityId()).getName()));

                    String units = "";
                    for (Squad squad : cityArmy.getArmy().getSquads()) {
                        units += squad.getUnit().getName() + ": " + (int) squad.getCount() + ", threshold: " + (int) squad.getThreshold() + " % ";
                    }
                    item.add(new Label("units", units));

                    Form<?> sendHome = new Form<Void>("sendHome") {
                        @Override
                        protected void onSubmit() {
                            PageParameters pageParameters = new PageParameters();
                            pageParameters.add("id", id.toString());

                            MarchingArmy army = new MarchingArmy();

                            army.setMovement(MovementType.Reinforcement);
                            Coordinates c = cityManager.getCityByName(selectedCity).getCoordinates();
                            army.setArmy(cityArmy.getArmy());
                            army.setCityIdFrom(cityArmy.getCityId());
                            army.setCoordinates(c);
                            army.setName(cityArmy.getName());
                            army.setOwnerCityId(cityArmy.getOwnerCityId());
                            army.setReturning(true);
                            army.setStolenFood(0);
                            army.setStolenGold(0);
                            army.setStolenStone(0);

                            TravelDistanceResolver travelDistanceResolver = new TravelDistanceResolver();
                            double distance = travelDistanceResolver.calculateDistance(c.getX_coordinate(), c.getY_coordinate(),
                                    cityManager.getCityByName(selectedCity).getCoordinates().getX_coordinate(), cityManager.getCityByName(selectedCity).getCoordinates().getY_coordinate());

                            int bonusSpeed = 0;
                            for (Research research : cityResearchManager.getAllFinishedResearchesOfPlayer(cityManager.getOwnerOfCity(cityArmy.getCityId()).getId())) {
                                for (String stat : research.getEffects().keySet()) {
                                    if (stat.equals("speed")) {
                                        bonusSpeed += research.getEffects().get(stat);
                                    }
                                }
                            }

                            int minSpeed = 500;
                            for (Squad squad : army.getArmy().getSquads()) {
                                if (minSpeed > (squad.getUnit().getSpeed() + bonusSpeed)) {
                                    minSpeed = squad.getUnit().getSpeed() + bonusSpeed;
                                }
                            }

                            java.util.Date date = new java.util.Date();
                            army.setTimeOfArrival(new Timestamp((date.getTime() + 1000 * 60 * (int) (distance / minSpeed))));

                            marchingArmyManager.createMarchingArmy(army);
                            cityArmyManager.sendArmy(cityArmy);
                            setResponsePage(ArmyPage.class, pageParameters);
                        }
                    };

                    item.add(sendHome);

                }
            };
            add(awayArmies);
        }
    }
}
